#ifndef _AMERICO_PLANE_H_
#define _AMERICO_PLANE_H_

#include "Vector.h"

template <typename TYPE>
class Plane
{
public:
    Vector3<TYPE> point1;
    Vector3<TYPE> point2;
    Vector3<TYPE> point3;
    Vector3<TYPE> normal;
 
    Plane();
    Plane(const Vector3<TYPE> &aFirstPoint, const Vector3<TYPE> &aSecondPoint, const Vector3<TYPE> &aThirdPoint);
    Plane(const Vector3<TYPE> &aPoint, const Vector3<TYPE> &aNormal);
    void InitWith3Points(const Vector3<TYPE> &aFirstPoint, const Vector3<TYPE> &aSecondPoint, const Vector3<TYPE> &aThirdPoint);
    void InitWithPointAndNormal(const Vector3<TYPE> &aPoint, const Vector3<TYPE> &aNormal);
    bool Inside(const Vector3<TYPE> &aPosition) const;
    bool operator==(const Plane &aPlane) const;
    bool operator!=(const Plane &aPlane) const;
};

template <typename TYPE>
Plane<TYPE>::Plane()
{
}

template <typename TYPE>
Plane<TYPE>::Plane(const Vector3<TYPE> &aFirstPoint, const Vector3<TYPE> &aSecondPoint, const Vector3<TYPE> &aThirdPoint)
{
    InitWith3Points(aFirstPoint, aSecondPoint, aThirdPoint);
}

template <typename TYPE>
Plane<TYPE>::Plane(const Vector3<TYPE> &aPoint, const Vector3<TYPE> &aNormal)
{
    InitWithPointAndNormal(aPoint, aNormal);
}

template <typename TYPE>
void Plane<TYPE>::InitWith3Points(const Vector3<TYPE> &aFirstPoint, const Vector3<TYPE> &aSecondPoint, const Vector3<TYPE> &aThirdPoint)
{
    point1 = aFirstPoint;
    point2 = aSecondPoint;
    point3 = aThirdPoint;
    normal = (point2-point1).Cross(point3-point1);
    float length = normal.Length();
    if(length != 0)
        normal /= length;
}

template <typename TYPE>
void Plane<TYPE>::InitWithPointAndNormal(const Vector3<TYPE> &aPoint, const Vector3<TYPE> &aNormal)
{
    point1 = aPoint;
    normal = aNormal;
    point2 = normal.Cross(point1);
    point3 = normal.Cross(point2);
}

template <typename TYPE>
bool Plane<TYPE>::Inside(const Vector3<TYPE> &aPosition) const
{
    if(normal.Dot(aPosition-point1) > 0)
    {
        return true;
    }
    return false;
}

template <typename TYPE>
bool Plane<TYPE>::operator==(const Plane<TYPE> &aPlane) const
{
    return ((normal == aPlane.normal) && (normal.Dot(aPlane.point1-point1)==0));
}

template <typename TYPE>
bool Plane<TYPE>::operator!=(const Plane<TYPE> &aPlane) const
{
    return (!operator==(aPlane));
}

#endif
